//! Strecken Simulations-Klasse


#include "carsimulation.h"
#include "ui_carsimulation.h"
#include <iostream>

quint16 dataPort = 45000;

/*! Konstruktor der Simulaion
 *
 *  Diese Funktion bereitet die ganze Umgebung vor
 *  und kriert Verbindungen zum Knopf drücken
 *  und für den Timer
 */
CarSimulation::CarSimulation(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CarSimulation)
{
   this->timer = new QTimer();
   count=1;
   laeuft=0;
   ui->setupUi(this);
   this->brdCtl = new sendReceiveControll();
   this->commCtl = new sendReceiveControll();
   connect(ui->bt_ab_laenge, SIGNAL(clicked()), this, SLOT(press_bt_start()));
   connect(timer, SIGNAL(timeout()), this, SLOT(nextStep()));
}

/*! Destruktor der Simulaion
 *
 *  loescht alle dynamsich kreierten Objekte
 *  und gibt den Speicher dieser frei.
 */
CarSimulation::~CarSimulation()
{
    delete ui;
    delete commCtl;
    delete brdCtl;
}


void CarSimulation::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

/*! Start/Stop-Knopf auswerten
 *
 * sorgt für das Ändern des Knopfnamens
 * und ruft Start oder Stopfunktion auf
 */
void CarSimulation::press_bt_start()
{
    if (laeuft==0)
    {
        laeuft=1;
        if(this->simStart())
        {
            QString test("Stop");
            ui->bt_ab_laenge->setText(test);
        }
    }
    else

    {
        laeuft=0;
        if(this->simStop())
        {
            QString test("Start");
            ui->bt_ab_laenge->setText(test);
        }
    }
}

/*! Starten der Simulation
 *
 * kreiert die Nötigen Verbindungen zum Datenempfangen
 * über Broadcast und direkt über UDP
 */
bool CarSimulation::simStart()
{
    connect(brdCtl, SIGNAL(broadcastReadyRead(QHostAddress, quint16, QByteArray)),
            this, SLOT(carBroadcoastReceive(QHostAddress,quint16,QByteArray)));

    connect(commCtl, SIGNAL(dataReadyRead(QHostAddress, quint16, QByteArray)),
            this, SLOT(carDataReceive(QHostAddress,quint16,QByteArray)));
    timer->start(1000);
    return true;
}

/*! Stoppen der Simulation
 *
 * löst die Verbindungen zum Datenempfangen
 * über Broadcast und direkt über UDP wieder
 */
bool CarSimulation::simStop()
{
    disconnect(brdCtl, SIGNAL(broadcastReadyRead(QHostAddress, quint16, QByteArray)),
               this, SLOT(carBroadcoastReceive(QHostAddress,quint16,QByteArray)));

    disconnect(commCtl, SIGNAL(dataReadyRead(QHostAddress, quint16, QByteArray)),
            this, SLOT(carDataReceive(QHostAddress,quint16,QByteArray)));
    timer->stop();
    return true;
}


/*! Broadcast empfangen
 *
 * wird aufgerufen sobald signalisiert wird,
 * dass neue Broadcast-Daten vorliegen
 */
void CarSimulation::carBroadcoastReceive(QHostAddress senderIP, quint16 senderPort,QByteArray data)
{
    QByteArray senddata;
    QByteArray temp("newcar");
    QString inList;

    if (data==temp)
    {
        senddata.clear();
        temp.clear();
        temp.setNum(count);
        inList.append(temp);
        inList.append(": ");
        inList.append(senderIP.toString());
        temp.clear();
        ui->lt_cars->addItem(inList);
        addCar2List(senderIP, count, count, count);
        temp.setNum(count);
        senddata.append(temp);
        senddata.append("@");
        senddata.append(temp);
        senddata.append("@");
        senddata.append(temp);
        temp.clear();

        brdCtl->sendData(senderIP, dataPort, senddata);
        count++;
    }
}

/*! neues Auto aufnehmen
 *
 * Funktion welche von carBroadcoastReceive aurgerufen wird,
 * sobald ein neues Auto sich im Netzwerk einwählt
 */
void CarSimulation::addCar2List(QHostAddress senderIP, int id, int spur, int weite)
{
        Car tempCar;
        tempCar.setId(id);
        tempCar.setSpeed(0);
        tempCar.setPanne(0);
        tempCar.setPosition(spur, weite);
        tempCar.setIp(senderIP);
        CarList.append(tempCar);
}

/*! Daten empfangen
 *
 * Funktion wird aufgerufen,
 * sobald ein Auto aktuelle Daten
 * oder ein OK schickt
 */
void CarSimulation::carDataReceive(QHostAddress senderIP, quint16 senderPort,QByteArray data)
{
    Car tempCar;
    QByteArray senddata;
    QByteArray temp("OK");
    senddata.clear();
    if (data==temp)
    {
        printf("Antwort OK");
        senddata.clear();
        temp.clear();
        senddata.append("Sim");
        for(int i=0; i<this->CarList.count();i++ )
        {
            senddata.append("!");
            tempCar=CarList.at(i);
            temp.setNum(tempCar.getId());
            senddata.append(temp);
            temp.clear();
            senddata.append("@");
            temp.setNum(tempCar.getSpeed());
            senddata.append(temp);
            temp.clear();
            senddata.append("@");
            temp.setNum(tempCar.getPanne());
            senddata.append(temp);
            temp.clear();
            senddata.append("@");
            temp.setNum(tempCar.getPosition().getSpur());
            senddata.append(temp);
            temp.clear();
            senddata.append("@");
            temp.setNum(tempCar.getPosition().getWeite());
            senddata.append(temp);
            temp.clear();
        }
        for (int i=0; i<this->CarList.count(); i++)
        {
            quint16 tempPort=dataPort+CarList.at(i).id;
            commCtl->sendData(CarList.at(i).ip, tempPort, senddata);
        }

    }
    else
    {
        QByteArray ok("OK");
        QList<QByteArray> listDaten = data.split('@');

        std::cout << "neue Wünsche sind eingetroffen" << std::endl;
        int id;
        if(listDaten.size() == 4)
        {
            id = listDaten.at(0).toInt();
            tempCar.id = id;
            tempCar.panne = listDaten.at(1).toInt();
            tempCar.sollSpeed = listDaten.at(2).toInt();
            tempCar.speed = CarList.at(id-1).speed;
            tempCar.sollSpur = listDaten.at(3).toInt();
            tempCar.ip = CarList.at(id-1).ip;
            tempCar.position = CarList.at(id-1).position;
            std::cout << "id:" << id << " sSpeed " << listDaten.at(2).toInt() << " sSpur " << listDaten.at(3).toInt() << std::endl;

            CarList.replace(id-1, tempCar);
            quint16 tempPort=dataPort+CarList.at(id-1).id;
            commCtl->sendData(senderIP, tempPort, ok);
        }
    }
}

/*! nächster Simulationsschritt
 *
 * Funktion wird aufgerufen,
 * sobald der Timer abgelaufen ist.
 * Die Wünsche der Vorrunde werden umgesetzt.
 * Auch wird die Geschiwindigkeit erhöht/verrringert
 * falls nötig
 * Die berechneten Daten werden alle Autos verschickt
 */
void CarSimulation::nextStep()
{
    Car tempCar;
    QByteArray senddata;
    QByteArray temp;
    senddata.clear();
    senddata.clear();
    temp.clear();
    senddata.append("Sim");
    for(int i=0; i<this->CarList.count();i++ )
    {
        senddata.append("!");
        tempCar=CarList.at(i);
        temp.setNum(tempCar.getId());
        senddata.append(temp);
        temp.clear();
        senddata.append("@");
        int besch, besch_alt;
        if (tempCar.getSpeed()<tempCar.getSollSpeed())
        {
            besch=(tempCar.getSpeed()*tempCar.getSpeed())+1;
            besch_alt=besch;
            int s=tempCar.getSpeed();
            s++;
            tempCar.setSpeed(s);
        }
        else if (tempCar.getSpeed()>tempCar.getSollSpeed())
        {
            besch=(tempCar.getSpeed()*tempCar.getSpeed())+1;
            besch_alt=besch;
            int s=tempCar.getSpeed();
            s--;
            tempCar.setSpeed(s);
        }
        else if (tempCar.getPanne()==1)
        {
            tempCar.setSpeed(0);
            besch=0;
            besch_alt=besch;
        }
        else
        {
            besch=(tempCar.getSpeed()*tempCar.getSpeed());
            besch_alt=besch;
        }
        temp.setNum(tempCar.getSpeed());

        senddata.append(temp);
        temp.clear();
        senddata.append("@");
        temp.setNum(tempCar.getPanne());
        senddata.append(temp);
        temp.clear();
        senddata.append("@");
        int spur = tempCar.getSollSpur();
        tempCar.setPosition(spur, tempCar.getWeite());
        temp.setNum(tempCar.getSpur());
        senddata.append(temp);
        temp.clear();
        senddata.append("@");
        int voran=(besch_alt+besch)/2;
        int weite=tempCar.getWeite();
        weite+=voran;
        tempCar.setPosition(tempCar.getSpur(), weite);

        if (tempCar.getPosition().getWeite()>=100000)
            tempCar.setPosition(tempCar.getSpur(), voran);

        temp.setNum(tempCar.getWeite());

        senddata.append(temp);
        temp.clear();

        CarList.replace(i, tempCar);
    }

    for (int i=0; i<this->CarList.count(); i++)
    {
        quint16 tempPort=dataPort+CarList.at(i).id;
        commCtl->sendData(CarList.at(i).ip, tempPort, senddata);
    }
}
